package com.permission.service.impl;

import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.permission.dao.SysAclMapper;
import com.permission.dao.SysAclModuleMapper;
import com.permission.dao.SysDeptMapper;
import com.permission.dto.AclDto;
import com.permission.dto.AclModuleLevelDto;
import com.permission.dto.DepLevelDto;
import com.permission.entity.SysAcl;
import com.permission.entity.SysAclModule;
import com.permission.entity.SysDept;
import com.permission.service.SysCoreService;
import com.permission.service.SysTreeService;
import com.permission.util.LevelUtil;

/**
 * 专门用于树形结构处理的service
 * @author jing
 */
@Service("sysTreeService")
public class SysTreeServiceImpl implements SysTreeService {
	
	@Autowired
    private SysDeptMapper sysDeptMapper;
    @Autowired
    private SysAclModuleMapper sysAclModuleMapper;
    @Autowired
    private SysCoreService sysCoreService;
    @Autowired
    private SysAclMapper sysAclMapper;

    /*=======================部门树 开始=============================*/	
	/**
	 * 获取部门树集合，并转化为DepLevelDto集合
	 */
	public List<DepLevelDto> getDepTree() {
		List<SysDept> list = sysDeptMapper.getAllDept();
		
		List<DepLevelDto> dtoList = Lists.newArrayList();
		//遍历从数据库取出的部门，转化为DepLevelDto
		for(SysDept dep:list){
			DepLevelDto dto = DepLevelDto.adapt(dep);
			dtoList.add(dto);
		}		
		return deptListToTree(dtoList);
	}
	
	/**
	 * 将部门集合按照level分组保存，并通过transformDeptTree将部门集合树返回
	 */
	public List<DepLevelDto> deptListToTree(List<DepLevelDto> deptLevelList) {
        if (CollectionUtils.isEmpty(deptLevelList)) {
            return Lists.newArrayList();
        }
        
        //创建一个Multimap对象，用于按level分组将部门集合保存，格式为【key:level，value: DepLevelDto集合】
        Multimap<String, DepLevelDto> levelDeptMap = ArrayListMultimap.create();
        //创建树菜单根节点
        List<DepLevelDto> rootList = Lists.newArrayList();
        //遍历部门集合，将部门集合保存到levelDeptMap，保存根节点到rootList
        for (DepLevelDto dto : deptLevelList) {
        	//将DepLevelDto集合按照 key:level，value:DepLevelDto对象保存
            levelDeptMap.put(dto.getLevel(), dto);
            //如果是根节点（level=0）,则保存到rootList
            if (LevelUtil.ROOT.equals(dto.getLevel())) {
                rootList.add(dto);
            }
        }
        
        // 对rootList按照seq从小到大排序
        Collections.sort(rootList, new Comparator<DepLevelDto>() {
            public int compare(DepLevelDto o1, DepLevelDto o2) {
                return o1.getSeq() - o2.getSeq();
            }
        });
        // 递归生成树
        transformDeptTree(rootList, LevelUtil.ROOT, levelDeptMap);
        return rootList;
    }
	
	/**
	 * 将分组好的部门集合，递归生成树
	 */
    public void transformDeptTree(List<DepLevelDto> deptLevelList, String level, Multimap<String, DepLevelDto> levelDeptMap) {
        for (int i = 0; i < deptLevelList.size(); i++) {
        	// 处理当前层级的数据
            DepLevelDto depLevelDto = deptLevelList.get(i);
            
            // 取出下一级DepLevelDto使用的level
            String nextLevel = LevelUtil.calculateLevel(level, depLevelDto.getId());
            
            List<DepLevelDto> tempDeptList = (List<DepLevelDto>) levelDeptMap.get(nextLevel);
            if (CollectionUtils.isNotEmpty(tempDeptList)) {
                // 排序
                Collections.sort(tempDeptList, deptSeqComparator);
                // 设置下一层部门
                depLevelDto.setDeptList(tempDeptList);
                // 进入到下一层处理
                transformDeptTree(tempDeptList, nextLevel, levelDeptMap);
            }
        }
    }
    
    //比较部门seq（树形菜单前后顺序）
    public Comparator<DepLevelDto> deptSeqComparator = new Comparator<DepLevelDto>() {
        public int compare(DepLevelDto o1, DepLevelDto o2) {
            return o1.getSeq() - o2.getSeq();
        }
    };

    /*=======================部门树 结束=============================*/
    
    
    
    /*=======================权限模块树 开始=============================*/
    /**
     * 返回权限模块树形菜单
     * （获取所有"权限模块"并转化为“权限模块树形”集合，返回最终树形菜单结果）
     * @return
     */
    public List<AclModuleLevelDto> aclModuleTree() {
        //获取所有权限模块
        List<SysAclModule> aclModuleList = sysAclModuleMapper.getAllAclModule();
        //创建一个“权限模块树形对象”集合
        List<AclModuleLevelDto> dtoList = Lists.newArrayList();
        //将权“限模模块集合”转化为“权限模块树形对象集合”
        for (SysAclModule aclModule : aclModuleList) {
            dtoList.add(AclModuleLevelDto.adapt(aclModule));
        }
        //将“权限模块树形对象集合”按照level分组
        return aclModuleListToTree(dtoList);
    }

    /**
     * 将"权限模块树形对象集合"按level分组,并新建一个List<AclModuleLevelDto>保存根节点
     * 并通过transformAclModuleTree函数返回最终结果
     * @param dtoList
     * @return
     */
    public List<AclModuleLevelDto> aclModuleListToTree(List<AclModuleLevelDto> dtoList) {
        if (CollectionUtils.isEmpty(dtoList)) {
            return Lists.newArrayList();
        }

        // level -> [aclmodule1, aclmodule2, ...] Map<String, List<Object>>
        //Multimap（一个key对应一个List）：可以对同一个key不断添加新的值，不会覆盖原来的值
        //用这个结构保存同一个level下面的所有子模块（key:level,value:AclModuleLevelDto集合）
        Multimap<String, AclModuleLevelDto> levelAclModuleMap = ArrayListMultimap.create();
        //创建一个跟节点
        List<AclModuleLevelDto> rootList = Lists.newArrayList();

        //遍历dtoList，在这里将对“权限模块树集合”根据level进行分组，保存到levelAclModuleMap
        for (AclModuleLevelDto dto : dtoList) {
            levelAclModuleMap.put(dto.getLevel(), dto);
            //判断是否是根节点
            if (LevelUtil.ROOT.equals(dto.getLevel())) {
                rootList.add(dto);
            }
        }

        //对树进行排序
        Collections.sort(rootList, aclModuleSeqComparator);

        //将根据level分组好的“权限模块集合”，保存到根节点，再递归保存子模块的子模块
        transformAclModuleTree(rootList, LevelUtil.ROOT, levelAclModuleMap);
        return rootList;
    }

    /**
     * 将根据level分组好的“权限模块集合”，保存到根节点，再递归保存子模块的子模块
     * 形成最终的树结构：
     * List<AclModuleLevelDto> （根节点）
     *     AclModuleLevelDto (权限模块树)
     *         AclModuleLevelDto
     *         ....
     *
     * @param dtoList   权限模块List
     * @param level     权限层级
     * @param levelAclModuleMap  【key：level, value（权限模块树集合）】
     */
    public void transformAclModuleTree(List<AclModuleLevelDto> dtoList, String level, Multimap<String, AclModuleLevelDto> levelAclModuleMap) {
        //将根节点集合遍历，将levelAclModuleMap（根据权限模块ID分组的“权限模块集合”）放入根节点
        for (int i = 0; i < dtoList.size(); i++) {
            AclModuleLevelDto dto = dtoList.get(i);

            //获取子权限模块的level
            String nextLevel = LevelUtil.calculateLevel(level, dto.getId());
            //根据nextLevel获取所有子权限模块
            List<AclModuleLevelDto> tempList = (List<AclModuleLevelDto>) levelAclModuleMap.get(nextLevel);
            //判断子模块是否为空，不为空则添加
            if (CollectionUtils.isNotEmpty(tempList)) {
                //排序
                Collections.sort(tempList, aclModuleSeqComparator);
                //添加子模块
                dto.setAclModuleList(tempList);
                //递归子模块的子模块
                transformAclModuleTree(tempList, nextLevel, levelAclModuleMap);
            }
        }
    }


    /**
     * 根据用户ID获取用户的“权限模块树”
     * @param userId
     * @return
     */
    public List<AclModuleLevelDto> userAclTree(int userId) {
        //根据用户ID获取权限
        List<SysAcl> userAclList = sysCoreService.getUserAclList(userId);
        //创建一个权限DTO
        List<AclDto> aclDtoList = Lists.newArrayList();
        //将权限集合转化为 权限DTO集合
        for (SysAcl acl : userAclList) {
            AclDto dto = AclDto.adapt(acl);
            dto.setHasAcl(true);
            dto.setChecked(true);
            aclDtoList.add(dto);
        }
        //将权限DTO集合转化为树结构并返回
        return aclListToTree(aclDtoList);
    }

    /**
     * 根据角色ID获取角色的“权限模块树”
     * 实现思路：
     * 1.获取用户拥有的全部权限
     * 2.根据角色ID获取该角色所有的权限
     * 3.获取系统的所有权限
     * 4.遍历"系统的所有权限"，和用户拥有的权限比对并标记
     * 5.将结果保存到新的集合，并通过aclListToTree方法转化为权限模块树返回
     * @param roleId
     * @return
     */
    public List<AclModuleLevelDto> roleTree(int roleId) {
        // 1、当前用户已分配的权限点
        List<SysAcl> userAclList = sysCoreService.getCurrentUserAclList();
        // 2、根据角色ID获取当前角色分配的权限点
        List<SysAcl> roleAclList = sysCoreService.getRoleAclList(roleId);
        // 3、保存当前系统所有权限点，并将用户拥有的权限做个标记
        List<AclDto> aclDtoList = Lists.newArrayList();

        //用户已分配的权限的ID集合，这里使用JDK8的高级语法“流遍历方式”
        Set<Integer> userAclIdSet = userAclList.stream().map(sysAcl -> sysAcl.getId()).collect(Collectors.toSet());
        //角色已经分配的权限的ID的集合
        Set<Integer> roleAclIdSet = roleAclList.stream().map(sysAcl -> sysAcl.getId()).collect(Collectors.toSet());

        //获取所有权限
        List<SysAcl> allAclList = sysAclMapper.getAll();
        for (SysAcl acl : allAclList) {
            //将SysAcl适配为AclDto
            AclDto dto = AclDto.adapt(acl);
            //判断用户是否拥有该权限
            if (userAclIdSet.contains(acl.getId())) {
                dto.setHasAcl(true);    //如果有则标记为“有”
            }
            //判断当前角色是否具有该权限
            if (roleAclIdSet.contains(acl.getId())) {
                dto.setChecked(true);   //如果有则标记为“选中”
            }
            //将权限保存到aclDtoList
            aclDtoList.add(dto);
        }
        //返回“权限模块树集合”
        return aclListToTree(aclDtoList);
    }

    /**
     * 将权限集合转化为“权限模块树集合”返回
     *
     * 内部实现：
     * 将"权限Dto集合"根据权限模块ID分组，并获取“权限模块树集合”
     * 将分组好的“权限Dto集合”通过 bindAclsWithOrder 函数放入“权限模块树集合”
     * @param  aclDtoList           权限DTO集合
     * @return aclModuleLevelList   权限模块树集合
     */
    public List<AclModuleLevelDto> aclListToTree(List<AclDto> aclDtoList) {
        //判断是否为空，空的话返回一个空List
        if (CollectionUtils.isEmpty(aclDtoList)) {
            return Lists.newArrayList();
        }

        //创建一个"权限模块树集合"对象，保存“权限模块树”
        List<AclModuleLevelDto> aclModuleLevelList = aclModuleTree();
        //key：权限模块ID，value：权限集合
        Multimap<Integer, AclDto> moduleIdAclMap = ArrayListMultimap.create();

        //遍历权限集合，将"权限集合"按"权限模块ID"分组保存到moduleIdAclMap
        for(AclDto acl : aclDtoList) {
            //判断权限是否可用，将可用的集合保存
            if (acl.getStatus() == 1) {
                moduleIdAclMap.put(acl.getAclModuleId(), acl);
            }
        }

        //将权限模块树
        bindAclsWithOrder(aclModuleLevelList, moduleIdAclMap);
        return aclModuleLevelList;
    }


    /**
     * 返回“权限模块树”
     * 实现思路：
     * 将“分组好的权限集合” 不断地递归放入 “权限模块树集合”
     * @param aclModuleLevelList    权限模块树集合
     * @param moduleIdAclMap        key：权限模块ID，value：权限集合
     */
    public void bindAclsWithOrder(List<AclModuleLevelDto> aclModuleLevelList, Multimap<Integer, AclDto> moduleIdAclMap) {
        //如果“权限模块树集合”为空的则停止
        if (CollectionUtils.isEmpty(aclModuleLevelList)) {
            return;
        }
        //遍历“权限模块树集合”，将所有的权限 根据权限模块ID分组整理，保存到权限模块对象
        for (AclModuleLevelDto dto : aclModuleLevelList) {
            //按照”权限模块ID“取出相应的“权限集合”
            List<AclDto> aclDtoList = (List<AclDto>)moduleIdAclMap.get(dto.getId());

            if (CollectionUtils.isNotEmpty(aclDtoList)) {
                //判断权限是否为空，不为空则进行排序
                Collections.sort(aclDtoList, aclSeqComparator);
                //将权限保存到权限模块树对象
                dto.setAclList(aclDtoList);
            }
            //递归
            bindAclsWithOrder(dto.getAclModuleList(), moduleIdAclMap);
        }
    }
    
    /*
     * 权限模块顺序比较规则
     */
    public Comparator<AclModuleLevelDto> aclModuleSeqComparator = new Comparator<AclModuleLevelDto>() {
        public int compare(AclModuleLevelDto o1, AclModuleLevelDto o2) {
            return o1.getSeq() - o2.getSeq();
        }
    };

    /*
     * 权限顺序比较规则
     */
    public Comparator<AclDto> aclSeqComparator = new Comparator<AclDto>() {
        public int compare(AclDto o1, AclDto o2) {
            return o1.getSeq() - o2.getSeq();
        }
    };

    /*=======================权限模块树 结束=============================*/
}
